package com.fish.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fish.common.exception.BusinessException;
import com.fish.common.result.ResultCode;
import com.fish.common.util.UserContext;
import com.fish.dao.mapper.*;
import com.fish.model.dto.NotificationDTO;
import com.fish.model.dto.NotificationQueryDTO;
import com.fish.model.entity.*;
import com.fish.model.vo.NotificationDetailVO;
import com.fish.model.vo.NotificationVO;
import com.fish.service.NotificationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 通知服务实现类
 */
@Slf4j
@Service
public class NotificationServiceImpl implements NotificationService {
    
    @Autowired
    private NotificationMapper notificationMapper;
    
    @Autowired
    private NotificationReceiverMapper receiverMapper;
    
    @Autowired
    private UserMapper userMapper;
    
    @Autowired
    private RoleMapper roleMapper;
    
    @Autowired
    private UserRoleMapper userRoleMapper;
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long sendNotification(NotificationDTO dto) {
        // 获取当前用户
        Long currentUserId = UserContext.getUserId();
        User sender = userMapper.selectById(currentUserId);
        if (sender == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }
        
        // 获取发送者的角色列表及最高权重
        List<Role> senderRoles = roleMapper.selectRolesByUserId(currentUserId);
        if (CollectionUtils.isEmpty(senderRoles)) {
            throw new BusinessException(ResultCode.ERROR.getCode(), "用户未分配角色，无法发送通知");
        }
        
        // 获取发送者最高权重
        int senderMaxWeight = senderRoles.stream()
                .mapToInt(Role::getWeight)
                .max()
                .orElse(0);
        
        // 创建通知实体
        Notification notification = new Notification();
        notification.setTitle(dto.getTitle());
        notification.setContent(dto.getContent());
        notification.setType(dto.getType());
        notification.setSenderId(currentUserId);
        notification.setSenderName(sender.getUsername());
        notification.setReceiverType(dto.getReceiverType());
        notification.setStatus(1); // 已发送
        
        // 根据接收者类型获取接收者列表
        Set<Long> receiverUserIds = new HashSet<>();
        
        if (dto.getReceiverType() == 1) {
            // 指定用户
            if (CollectionUtils.isEmpty(dto.getReceiverUserIds())) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "请指定接收用户");
            }
            receiverUserIds.addAll(dto.getReceiverUserIds());
            
        } else if (dto.getReceiverType() == 2) {
            // 指定角色
            if (CollectionUtils.isEmpty(dto.getReceiverRoleIds())) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "请指定接收角色");
            }
            
            // 验证权重：发送者必须有权限给这些角色发送通知
            List<Role> targetRoles = roleMapper.selectBatchIds(dto.getReceiverRoleIds());
            for (Role targetRole : targetRoles) {
                if (targetRole.getWeight() >= senderMaxWeight) {
                    throw new BusinessException(ResultCode.ERROR.getCode(), 
                            "权限不足：无法向权重不低于自己的角色[" + targetRole.getRoleName() + "]发送通知");
                }
            }
            
            // 保存角色ID列表
            String roleIds = dto.getReceiverRoleIds().stream()
                    .map(String::valueOf)
                    .collect(Collectors.joining(","));
            notification.setReceiverRoleIds(roleIds);
            
            // 获取这些角色下的所有用户
            LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(UserRole::getRoleId, dto.getReceiverRoleIds());
            List<UserRole> userRoles = userRoleMapper.selectList(wrapper);
            receiverUserIds.addAll(userRoles.stream()
                    .map(UserRole::getUserId)
                    .collect(Collectors.toSet()));
            
        } else if (dto.getReceiverType() == 3) {
            // 全部用户 - 只能发送给权重低于自己的用户
            LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.eq(User::getStatus, 1);
            List<User> allUsers = userMapper.selectList(userWrapper);
            
            // 过滤出权重低于发送者的用户
            for (User user : allUsers) {
                List<Role> userRoles = roleMapper.selectRolesByUserId(user.getId());
                int userMaxWeight = userRoles.stream()
                        .mapToInt(Role::getWeight)
                        .max()
                        .orElse(0);
                
                // 只添加权重低于发送者的用户
                if (userMaxWeight < senderMaxWeight) {
                    receiverUserIds.add(user.getId());
                }
            }
        }
        
        // 移除发送者自己
        receiverUserIds.remove(currentUserId);
        
        if (receiverUserIds.isEmpty()) {
            throw new BusinessException(ResultCode.ERROR.getCode(), "没有符合条件的接收者");
        }
        
        // 保存通知
        notificationMapper.insert(notification);
        
        // 批量创建接收者记录
        List<NotificationReceiver> receivers = new ArrayList<>();
        Map<Long, String> userIdNameMap = getUserIdNameMap(receiverUserIds);
        
        for (Long receiverId : receiverUserIds) {
            NotificationReceiver receiver = new NotificationReceiver();
            receiver.setNotificationId(notification.getId());
            receiver.setReceiverId(receiverId);
            receiver.setReceiverName(userIdNameMap.getOrDefault(receiverId, "未知用户"));
            receiver.setIsRead(0);
            receivers.add(receiver);
        }
        
        // 批量插入
        receivers.forEach(receiverMapper::insert);
        
        log.info("用户[{}]发送通知[{}]成功，接收人数：{}", currentUserId, notification.getId(), receivers.size());
        return notification.getId();
    }
    
    @Override
    public IPage<NotificationVO> getMyNotifications(NotificationQueryDTO dto) {
        Long currentUserId = UserContext.getUserId();
        
        // 分页参数
        Page<NotificationVO> page = new Page<>(
                dto.getPageNum() != null ? dto.getPageNum() : 1,
                dto.getPageSize() != null ? dto.getPageSize() : 10
        );
        
        // 构建查询条件
        LambdaQueryWrapper<NotificationReceiver> receiverWrapper = new LambdaQueryWrapper<>();
        receiverWrapper.eq(NotificationReceiver::getReceiverId, currentUserId);
        
        // 是否只查询未读
        if (dto.getUnreadOnly() != null && dto.getUnreadOnly()) {
            receiverWrapper.eq(NotificationReceiver::getIsRead, 0);
        }
        
        receiverWrapper.orderByDesc(NotificationReceiver::getCreateTime);
        
        // 查询接收者记录
        IPage<NotificationReceiver> receiverPage = receiverMapper.selectPage(
                new Page<>(page.getCurrent(), page.getSize()),
                receiverWrapper
        );
        
        if (CollectionUtils.isEmpty(receiverPage.getRecords())) {
            return page;
        }
        
        // 获取通知ID列表
        List<Long> notificationIds = receiverPage.getRecords().stream()
                .map(NotificationReceiver::getNotificationId)
                .collect(Collectors.toList());
        
        // 查询通知详情
        LambdaQueryWrapper<Notification> notificationWrapper = new LambdaQueryWrapper<>();
        notificationWrapper.in(Notification::getId, notificationIds);
        
        // 标题模糊查询
        if (StringUtils.hasText(dto.getTitle())) {
            notificationWrapper.like(Notification::getTitle, dto.getTitle());
        }
        
        // 通知类型
        if (dto.getType() != null) {
            notificationWrapper.eq(Notification::getType, dto.getType());
        }
        
        List<Notification> notifications = notificationMapper.selectList(notificationWrapper);
        Map<Long, Notification> notificationMap = notifications.stream()
                .collect(Collectors.toMap(Notification::getId, n -> n));
        
        // 构建VO列表
        List<NotificationVO> voList = new ArrayList<>();
        for (NotificationReceiver receiver : receiverPage.getRecords()) {
            Notification notification = notificationMap.get(receiver.getNotificationId());
            if (notification != null) {
                NotificationVO vo = new NotificationVO();
                vo.setId(notification.getId());
                vo.setTitle(notification.getTitle());
                vo.setContent(notification.getContent());
                vo.setType(notification.getType());
                vo.setTypeName(getTypeName(notification.getType()));
                vo.setSenderId(notification.getSenderId());
                vo.setSenderName(notification.getSenderName());
                vo.setIsRead(receiver.getIsRead());
                vo.setReadTime(receiver.getReadTime());
                vo.setCreateTime(notification.getCreateTime());
                vo.setReceiverId(receiver.getId());
                voList.add(vo);
            }
        }
        
        page.setRecords(voList);
        page.setTotal(receiverPage.getTotal());
        return page;
    }
    
    @Override
    public NotificationDetailVO getNotificationDetail(Long id) {
        Notification notification = notificationMapper.selectById(id);
        if (notification == null) {
            throw new BusinessException(ResultCode.ERROR.getCode(), "通知不存在");
        }
        
        NotificationDetailVO vo = new NotificationDetailVO();
        BeanUtil.copyProperties(notification, vo);
        vo.setTypeName(getTypeName(notification.getType()));
        vo.setReceiverTypeName(getReceiverTypeName(notification.getReceiverType()));
        vo.setStatusName(getStatusName(notification.getStatus()));
        
        // 统计接收人数和已读人数
        LambdaQueryWrapper<NotificationReceiver> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(NotificationReceiver::getNotificationId, id);
        Long totalReceivers = receiverMapper.selectCount(wrapper);
        
        LambdaQueryWrapper<NotificationReceiver> readWrapper = new LambdaQueryWrapper<>();
        readWrapper.eq(NotificationReceiver::getNotificationId, id)
                .eq(NotificationReceiver::getIsRead, 1);
        Long readCount = receiverMapper.selectCount(readWrapper);
        
        vo.setTotalReceivers(totalReceivers);
        vo.setReadCount(readCount);
        
        return vo;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void markAsRead(Long receiverId) {
        NotificationReceiver receiver = receiverMapper.selectById(receiverId);
        if (receiver == null) {
            throw new BusinessException(ResultCode.ERROR.getCode(), "通知记录不存在");
        }
        
        // 验证权限
        Long currentUserId = UserContext.getUserId();
        if (!receiver.getReceiverId().equals(currentUserId)) {
            throw new BusinessException(ResultCode.FORBIDDEN);
        }
        
        if (receiver.getIsRead() == 0) {
            receiver.setIsRead(1);
            receiver.setReadTime(LocalDateTime.now());
            receiverMapper.updateById(receiver);
        }
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void markAllAsRead() {
        Long currentUserId = UserContext.getUserId();
        
        // 查询所有未读通知
        LambdaQueryWrapper<NotificationReceiver> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(NotificationReceiver::getReceiverId, currentUserId)
                .eq(NotificationReceiver::getIsRead, 0);
        
        List<NotificationReceiver> receivers = receiverMapper.selectList(wrapper);
        if (!CollectionUtils.isEmpty(receivers)) {
            LocalDateTime now = LocalDateTime.now();
            for (NotificationReceiver receiver : receivers) {
                receiver.setIsRead(1);
                receiver.setReadTime(now);
                receiverMapper.updateById(receiver);
            }
        }
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteNotification(Long receiverId) {
        NotificationReceiver receiver = receiverMapper.selectById(receiverId);
        if (receiver == null) {
            throw new BusinessException(ResultCode.ERROR.getCode(), "通知记录不存在");
        }
        
        // 验证权限
        Long currentUserId = UserContext.getUserId();
        if (!receiver.getReceiverId().equals(currentUserId)) {
            throw new BusinessException(ResultCode.FORBIDDEN);
        }
        
        receiverMapper.deleteById(receiverId);
    }
    
    @Override
    public Long getUnreadCount() {
        Long currentUserId = UserContext.getUserId();
        
        LambdaQueryWrapper<NotificationReceiver> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(NotificationReceiver::getReceiverId, currentUserId)
                .eq(NotificationReceiver::getIsRead, 0);
        
        return receiverMapper.selectCount(wrapper);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recallNotification(Long notificationId) {
        Notification notification = notificationMapper.selectById(notificationId);
        if (notification == null) {
            throw new BusinessException(ResultCode.ERROR.getCode(), "通知不存在");
        }
        
        // 验证权限：只有发送者可以撤回
        Long currentUserId = UserContext.getUserId();
        if (!notification.getSenderId().equals(currentUserId)) {
            throw new BusinessException(ResultCode.FORBIDDEN.getCode(), "只有发送者可以撤回通知");
        }
        
        // 已撤回的不能重复撤回
        if (notification.getStatus() == 2) {
            throw new BusinessException(ResultCode.ERROR.getCode(), "通知已撤回");
        }
        
        // 更新状态为已撤回
        notification.setStatus(2);
        notificationMapper.updateById(notification);
        
        log.info("用户[{}]撤回通知[{}]", currentUserId, notificationId);
    }
    
    /**
     * 获取用户ID和用户名映射
     */
    private Map<Long, String> getUserIdNameMap(Set<Long> userIds) {
        if (CollectionUtils.isEmpty(userIds)) {
            return new HashMap<>();
        }
        
        List<User> users = userMapper.selectBatchIds(userIds);
        return users.stream()
                .collect(Collectors.toMap(User::getId, User::getUsername));
    }
    
    /**
     * 获取通知类型名称
     */
    private String getTypeName(Integer type) {
        if (type == null) {
            return "未知";
        }
        switch (type) {
            case 1:
                return "系统通知";
            case 2:
                return "角色通知";
            case 3:
                return "个人通知";
            default:
                return "未知";
        }
    }
    
    /**
     * 获取接收者类型名称
     */
    private String getReceiverTypeName(Integer receiverType) {
        if (receiverType == null) {
            return "未知";
        }
        switch (receiverType) {
            case 1:
                return "指定用户";
            case 2:
                return "指定角色";
            case 3:
                return "全部用户";
            default:
                return "未知";
        }
    }
    
    /**
     * 获取状态名称
     */
    private String getStatusName(Integer status) {
        if (status == null) {
            return "未知";
        }
        switch (status) {
            case 0:
                return "草稿";
            case 1:
                return "已发送";
            case 2:
                return "已撤回";
            default:
                return "未知";
        }
    }
}

